﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProjectRoughWork
{
    class EventManager : IEventManager
    {
        /// <summary>
        /// Default Constructor. Intializes event queues, EventListenerMap and the current active queue
        /// </summary>

        public EventManager()
        {
            activeQueue = 0;
            registeredEvents = new Queue<IEventData>[2];

            registeredEvents[0] = new Queue<IEventData>();
            registeredEvents[1] = new Queue<IEventData>();


            registeredListeners = new Dictionary<string, List<IEventListener>>();
        }

        /// <summary>
        /// Returns an instance of the event manager, initializing the class if necessary
        /// </summary>
        /// <returns>An instance of the EventManager</returns>

        public static IEventManager GetInstance()
        {
            if (pInstance == null)
            {
                pInstance = new EventManager();
            }
            return pInstance;
        }

        /// <summary>
        /// Adds a new EventListener to the EventListener Map
        /// </summary>
        /// <param name="eventType">The event type that the EventListener will subscribe to</param>
        /// <param name="newListener">The new EventListener to be added</param>
        /// <returns>Returns true if insertion was successful, returns false if the insertion failed or the Listener is already attached</returns>

        public bool VAddListener(string eventType, IEventListener newListener)
        {
            //Check if the event type is registeed

            if (registeredListeners.ContainsKey(eventType))
            {
                List<IEventListener> listenerTable = registeredListeners[eventType];

                //Check if the listener already exists in the listener list. If not, add the listener
                ///
                /// Xbox uses a Silverlight version of the .NET framework.
                /// List.(T).Exists does not exist in the silverlight version.
                /// List(T).Contains is the equivalent 
                /// (http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.95).aspx
                ///
                if (!registeredListeners[eventType].Contains(newListener))
                //if (!registeredListeners[eventType].Exists(delegate(IEventListener test) { return (test == newListener); }))
                {
                    registeredListeners[eventType].Add(newListener);
                    return true;
                }
            }
            else
            {
                List<IEventListener> listenerTable = new List<IEventListener>();

                listenerTable.Add(newListener);

                registeredListeners.Add(eventType, listenerTable);
            }

            return false;
        }

        /// <summary>
        /// Remove a listener from the EventListener Map
        /// </summary>
        /// <param name="eventType">The event type to remove the Listener from</param>
        /// <param name="targetListener">The Listener to be removed</param>
        /// <returns>Returns true if the listener was successfully removed. Returns false otherwise</returns>

        public bool VDelListener(string eventType, IEventListener targetListener)
        {
            bool found = false;

            if (registeredListeners.ContainsKey(eventType))
            {
                found = registeredListeners[eventType].Remove(targetListener);
            }
            return found;
        }

        /// <summary>
        /// Adds the given event to the event queue
        /// </summary>
        /// <param name="newEvent">The new event to be queued</param>
        /// <returns>Returns true if queueing was successful. Returns false if event type isn't registered</returns>

        public bool VQueueEvent(IEventData newEvent)
        {
            if (registeredListeners.ContainsKey(newEvent.VGetEventType()))
            {
                registeredEvents[activeQueue].Enqueue(newEvent);
                return true;
            }

            return false;
        }
        
        /// <summary>
        /// Removes an event from the queue
        /// </summary>
        /// <param name="targetEvent">The event to be removed</param>
        /// <returns>Returns true if removal of the event was successful</returns>
        
        public bool VDequeEvent(IEventData targetEvent)
        {
            //registeredEvents.Deq
            return true;
        }

        /// <summary>
        /// Immediately processes the given event, bypassing the queue
        /// </summary>
        /// <param name="newEvent">The event to be processed immediately</param>
        /// <returns>Returns true if the event was processed, false otherwise</returns>

        public bool VTriggerEvent(IEventData newEvent)
        {
            //If there are listeners registered for the event type of the event, retrieve them and have them process the event.

            if (registeredListeners.ContainsKey(newEvent.VGetEventType()))
            {
                List<IEventListener> listenerList = registeredListeners[newEvent.VGetEventType()];

                foreach (IEventListener tempListener in listenerList)
                {
                    tempListener.VHandleEvent(newEvent);
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// Runs the EventManager, making it process it's currently active queue
        /// </summary>

        public void VRun()
        {
            //Create a local variable with the current active que and change the global active queue

            int currentQueue = activeQueue;
            activeQueue = 1 - activeQueue;

            //Clear the new active queue

            if (registeredEvents[activeQueue].Count > 0)
            {
                registeredEvents[activeQueue].Clear();
            }

            //Loop through the entire queue

            while (registeredEvents[currentQueue].Count > 0)
            {
                //Retrieve an event from the queue and the list of listener's subscribed to the event type of the event

                IEventData currentEvtData = registeredEvents[currentQueue].Dequeue();

                List<IEventListener> listenerList = registeredListeners[currentEvtData.VGetEventType()];

                //Loop through the list of event listeners and have them process the event

                foreach (IEventListener currentListener in listenerList)
                {
                    currentListener.VHandleEvent(currentEvtData);
                }
            }
        }

        //Data Members

        private int activeQueue;
        Queue<IEventData>[] registeredEvents;
        Dictionary<string, List<IEventListener>> registeredListeners;
        private static IEventManager pInstance;
        
        
    }
}
